﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using EPiServer.Web.Hosting;
using Microsoft.WindowsAzure.StorageClient;
using System.Security.Cryptography;

namespace DBLOG.Azure.VirtualPathProvider.Entities
{
    /// <summary>
    /// Stream that wraps a CloudFile
    /// </summary>
    /// <remarks>When Close is called the stream is uploaded to the path defined by the CloudFile</remarks>
    public class CloudStream : MemoryStream
    {
        private CloudFile _CloudFile { get; set; }

        private CloudStream()
        {
            // Parameterless constructor should not be called and is therefore private
        }

        /// <summary>
        /// Creates a new CloudStream
        /// </summary>
        /// <param name="file">The CloudFile defines where in blob storage the stream should be uploaded</param>
        public CloudStream(CloudFile file)
        {
            this._CloudFile = file;
        }

        public override void Close()
        {
            string filePath = this._CloudFile.VirtualPath;

            string containerName = this._CloudFile.ContainerName;

            CloudBlob blob = BlobStorageDataFactory.Instance.GetFile(filePath, containerName);

            // HACK: An MD5 error is thrown if not manually computed - Azure bug?
            var hash = ComputeContentHashAndResetPosition(this);

            blob.Properties.ContentMD5 = hash;

            this.Position = 0;

            blob.UploadFromStream(this);

            base.Close();
        }

        /// <summary>
        /// Helper method to compute MD5 hash for the stream
        /// </summary>
        private static string ComputeContentHashAndResetPosition(Stream source)
        {
            byte[] hash;
            source.Seek(0, SeekOrigin.Begin);
            using (var md5 = MD5.Create())
            {
                hash = md5.ComputeHash(source);
            }

            source.Seek(0, SeekOrigin.Begin);

            return Convert.ToBase64String(hash);
        }
    }
}
